﻿using IronPython.Runtime;
using Microsoft.EntityFrameworkCore;
using System;
using System.Collections.Generic;
using System.ComponentModel.DataAnnotations;
using System.Linq;

namespace CoreLims.Models.CoreLims
{
    using Spec = SampleSpec;

    public static class SampleSpecExtension
    {
        #region 指标相关
        public static List<Spec> getSpecList(this SampleSpec spec, CoreLimsContext dbContext) => 
            dbContext.Spec.Where(s => s.IsCollection == false).OrderBy(x => x.Code).ToList();

        /// <summary>
        /// 根据 一级分类 获取指标数据
        /// </summary>
        /// <param name="Classification"></param>
        /// <returns></returns>
        public static List<Spec> getSpecListByFirstGroup(this SampleSpec spec, CoreLimsContext dbContext, string FirstGroup) => 
            dbContext.Spec.Where(s => s.FirstGroup == FirstGroup && s.IsCollection == false).OrderBy(x => x.Code).ToList();

        /// <summary>
        /// 根据 二级分类 获取指标数据
        /// </summary>
        /// <returns></returns>
        public static List<Spec> getSpecListBySecondGroup(this SampleSpec spec, CoreLimsContext dbContext, string SecondGroup) =>
            dbContext.Spec.Where(s => s.SecondGroup == SecondGroup && s.IsCollection == false).OrderBy(x => x.Code).ToList();

        /// <summary>
        /// 根据 一级、二级 分类，获取指标数据
        /// </summary>
        /// <param name="spec"></param>
        /// <param name="dbContext"></param>
        /// <param name="FirstGroup">一级分类</param>
        /// <param name="SecondGroup">二级分类</param>
        /// <returns></returns>
        public static List<Spec> getSpecListByFirstAndSecond(this SampleSpec spec, CoreLimsContext dbContext, string FirstGroup, string SecondGroup)
        {
            if (FirstGroup == "全部")
                return dbContext.Spec.Where(s => s.IsCollection == false).OrderBy(x => x.Code).ToList();

            if (string.IsNullOrEmpty(SecondGroup))
                return dbContext.Spec.Where(s => s.FirstGroup == FirstGroup && s.IsCollection == false).OrderBy(x => x.Code).ToList();
            else
                return dbContext.Spec.Where(s => s.FirstGroup == FirstGroup && s.SecondGroup == SecondGroup && s.IsCollection == false).OrderBy(x => x.Code).ToList();
        }

        public static List<Spec> getSpec(this SampleSpec spec, CoreLimsContext dbContext) => 
            dbContext.Spec.Where(s => s.IsCollection == false).ToList().OrderBy(x => x.Code).ToList();

        public static Spec getSpec(this SampleSpec spec, CoreLimsContext dbContext, string Id) => 
            dbContext.Spec.FirstOrDefault(m => m.Id == Id);

        /// <summary>
        /// 根据 指标代码 查询指标
        /// </summary>
        /// <param name="spec"></param>
        /// <param name="dbContext"></param>
        /// <param name="Code"></param>
        /// <returns></returns>
        public static Spec getSpecByCode(this SampleSpec spec, CoreLimsContext dbContext, string Code) => 
            dbContext.Spec.FirstOrDefault(m => m.Code == Code && m.IsCollection == false);

        /// <summary>
        /// 根据 名称 模糊查询
        /// </summary>
        /// <param name="Name"></param>
        /// <returns></returns>
        public static List<Spec> getSpecByName(this SampleSpec spec, CoreLimsContext dbContext, string Name) => 
            dbContext.Spec.Where(m => m.Name.Contains(Name) && m.IsCollection == false).ToList().OrderBy(x => x.Code).ToList();

        public static string AddSpec(this SampleSpec spec, CoreLimsContext dbContext)
        {
            spec.Id = SAMPLE._newId();
            spec.ReleaseStatus = Common.Status.草稿.ToString();
            spec.Version = 1;
            spec.Enable = true;
            spec.IsCollection = false;
            dbContext.Add(spec);
            dbContext.SaveChanges();
            return "指标添加成功！";
        }

        /// <summary>
        /// 更新指标
        /// </summary>
        /// <param name="spec"></param>
        /// <param name="dbContext"></param>
        /// <param name="UpdateAll">如果更新所有项，UpdateAll=true 否则 =false </param>
        /// <returns></returns>
        public static string UpdateSpec(this SampleSpec spec, CoreLimsContext dbContext, Boolean UpdateAll = true)
        {
            SampleSpec Spec = SAMPLE.Spec.getSpec(dbContext, spec.Id);
            if (UpdateAll)
            {
                Spec.Copy(spec);
            }
            else
            {
                Spec.CopyText(spec);
            }

            dbContext.Update(Spec);
            dbContext.SaveChanges();
            return "指标信息更新成功！";
        }

        public static string DeleteSpec(this SampleSpec spec, CoreLimsContext dbContext, string Id)
        {
            SampleSpec Spec = SAMPLE.Spec.getSpec(dbContext, Id);

            // 删除指标时，应检查是否有分析定义该指标为默认指标，有则不能删除。
            var anaList = dbContext.Analyte.Where(s => s.DefaultSpecId == Spec.Id)
                .Select(s => s.Name).ToArray();

            if (anaList.Count() != 0)
            {
                var temp = "";
                foreach (var ana in anaList)
                {
                    temp = temp + ana + ",";
                }
                return "以下分析项与当前指标有关联：" + temp;
            }

            dbContext.Remove(Spec);
            dbContext.SaveChanges();
            return "删除成功！";
        }

        public static string UpdateSpecEnable(this SampleSpec spec, CoreLimsContext dbContext, string Id, string Enable)
        {
            SampleSpec Spec = SAMPLE.Spec.getSpec(dbContext, Id);

            if (Enable == "true")
                Spec.Enable = true;
            else
                Spec.Enable = false;

            dbContext.Update(Spec);
            dbContext.SaveChanges();
            return "状态更新成功！";
        }

        public static string UpdateSpecAcceptanceRules(this SampleSpec spec, CoreLimsContext dbContext, string Id, string AcceptanceRules)
        {
            SampleSpec Spec = SAMPLE.Spec.getSpec(dbContext, Id);
            Spec.AcceptanceRules = AcceptanceRules;

            dbContext.Update(Spec);
            dbContext.SaveChanges();
            return "规则更新成功！";
        }

        /// <summary>
        /// 更新 验收标准
        /// </summary>
        /// <param name="spec"></param>
        /// <param name="dbContext"></param>
        /// <param name="Id"></param>
        /// <param name="AcceptanceCriteria"></param>
        /// <returns></returns>
        public static string UpdateSpecAcceptanceCriteria(this SampleSpec spec, CoreLimsContext dbContext, string Id, string AcceptanceCriteria)
        {
            SampleSpec Spec = SAMPLE.Spec.getSpec(dbContext, Id);
            Spec.AcceptanceCriteria = AcceptanceCriteria;

            dbContext.Update(Spec);
            dbContext.SaveChanges();
            return "验收标准更新成功！";
        }

        public static string UpdateLowA(this SampleSpec spec, CoreLimsContext dbContext, string Id, string lowA)
        {
            decimal lowa;
            var isdecimal = decimal.TryParse(lowA, out lowa);
            if (!isdecimal)
                return " LowA 的值只能是数字，不能是文本！";

            SampleSpec Spec = SAMPLE.Spec.getSpec(dbContext, Id);
            Spec.LowA = lowa.ToString();

            dbContext.Update(Spec);
            dbContext.SaveChanges();
            return "LowA更新成功！";
        }

        public static string UpdateLowB(this SampleSpec spec, CoreLimsContext dbContext, string Id, string lowB)
        {
            decimal lowb;
            var isdecimal = decimal.TryParse(lowB, out lowb);
            if (!isdecimal)
                return " LowB 的值只能是数字，不能是文本！";

            SampleSpec Spec = SAMPLE.Spec.getSpec(dbContext, Id);
            Spec.LowB = lowb.ToString();

            dbContext.Update(Spec);
            dbContext.SaveChanges();
            return "LowB更新成功！";
        }

        public static string UpdateHighB(this SampleSpec spec, CoreLimsContext dbContext, string Id, string highB)
        {
            decimal highb;
            var isdecimal = decimal.TryParse(highB, out highb);
            if (!isdecimal)
                return " HighB 的值只能是数字，不能是文本！";

            SampleSpec Spec = SAMPLE.Spec.getSpec(dbContext, Id);
            Spec.HighB = highb.ToString();

            dbContext.Update(Spec);
            dbContext.SaveChanges();
            return "HighB更新成功！";
        }

        public static string UpdateHighA(this SampleSpec spec, CoreLimsContext dbContext, string Id, string highA)
        {
            decimal higha;
            var isdecimal = decimal.TryParse(highA, out higha);
            if (!isdecimal)
                return " HighA 的值只能是数字，不能是文本！";

            SampleSpec Spec = SAMPLE.Spec.getSpec(dbContext, Id);
            Spec.HighA = higha.ToString();

            dbContext.Update(Spec);
            dbContext.SaveChanges();
            return "HighA更新成功！";
        }

        public static string UpdateStandrdValue(this SampleSpec spec, CoreLimsContext dbContext, string Id, string standrdValue)
        {
            decimal stand;
            var isdecimal = decimal.TryParse(standrdValue, out stand);
            if (!isdecimal)
                return "标准值只能是数字，不能是文本！";

            SampleSpec Spec = SAMPLE.Spec.getSpec(dbContext, Id);
            Spec.StandardValue = stand.ToString();

            dbContext.Update(Spec);
            dbContext.SaveChanges();
            return "标准值更新成功！";
        }

        /// <summary>
        /// 复制记录内容，ID不复制
        /// </summary>
        /// <param name="supplier"></param>
        /// <param name="other"></param>
        /// <returns></returns>
        public static SampleSpec Copy(this SampleSpec spec, SampleSpec other)
        {
            spec.Code = other.Code;
            spec.Name = other.Name;
            spec.FirstGroup = other.FirstGroup;
            spec.SecondGroup = other.SecondGroup;
            spec.Description = other.Description;
            spec.LowA = other.LowA;
            spec.LowB = other.LowB;
            spec.StandardValue = other.StandardValue;
            spec.HighB = other.HighB;
            spec.HighA = other.HighA;
            spec.AcceptanceCriteria = other.AcceptanceCriteria;
            spec.AcceptanceRules = other.AcceptanceRules;
            spec.Version = other.Version;
            spec.ReleaseStatus = other.ReleaseStatus;
            spec.Enable = other.Enable;
            spec.IsCollection = false;

            return spec;
        }

        /// <summary>
        /// 不包含 规则、版本、状态、是否启用
        /// </summary>
        /// <param name="spec"></param>
        /// <param name="other"></param>
        /// <returns></returns>
        public static SampleSpec CopyText(this SampleSpec spec, SampleSpec other)
        {
            spec.Code = other.Code;
            spec.Name = other.Name;
            spec.FirstGroup = other.FirstGroup;
            spec.SecondGroup = other.SecondGroup;
            spec.Description = other.Description;
            spec.LowA = other.LowA;
            spec.LowB = other.LowB;
            spec.StandardValue = other.StandardValue;
            spec.HighB = other.HighB;
            spec.HighA = other.HighA;
            spec.AcceptanceCriteria = other.AcceptanceCriteria;
            spec.IsCollection = false;
            //spec.AcceptanceRules = other.AcceptanceRules;
            //spec.Version = other.Version;
            //spec.ReleaseStatus = other.ReleaseStatus;
            //spec.Enable = other.Enable;

            return spec;
        }

        /// <summary>
        /// 根据自身ID从关系表中获得与自身关联的分析项列表
        /// </summary>
        /// <param name="SpecId"></param>
        /// <returns></returns>
        public static List<SampleAnalyte> getSpecRelationAnalytes(this SampleSpec spec, CoreLimsContext dbcontext)
        {
            var list = dbcontext.Analyte.Where(s => s.DefaultSpecId == spec.Id)
                .Select(s => new { s.Id })
                .ToArray();

            string[] array = new string[list.Length];
            for (int i = 0; i < list.Length; i++)
            {
                array[i] = list[i].Id;
            }

            var analist = dbcontext.Analyte.Where(s => array.Contains(s.Id)).ToList();

            return analist;
        }

        #endregion

        #region 指标集相关

        public static List<Spec> getSpecCollectionList(this SampleSpec spec, CoreLimsContext dbContext) =>
            dbContext.Spec.Where(s => s.IsCollection == true && string.IsNullOrEmpty(s.CollectionId)).OrderBy(x => x.Code).ToList();

        /// <summary>
        /// 根据 一级分类 获取指标集数据
        /// </summary>
        /// <param name="Classification"></param>
        /// <returns></returns>
        public static List<Spec> getSpecCollectionListByFirstGroup(this SampleSpec spec, CoreLimsContext dbContext, string FirstGroup) =>
            dbContext.Spec.Where(s => s.FirstGroup == FirstGroup && s.IsCollection == true && string.IsNullOrEmpty(s.CollectionId))
            .OrderBy(x => x.Code).ToList();

        /// <summary>
        /// 根据 一级、二级 分类，获取指标集数据
        /// </summary>
        /// <param name="spec"></param>
        /// <param name="dbContext"></param>
        /// <param name="FirstGroup">一级分类</param>
        /// <param name="SecondGroup">二级分类</param>
        /// <returns></returns>
        public static List<Spec> getSpecCollectionFirstAndBySecond(this SampleSpec spec, CoreLimsContext dbContext, string FirstGroup, string SecondGroup)
        {
            if (FirstGroup == "全部")
                return dbContext.Spec.Where(s => s.IsCollection == true && string.IsNullOrEmpty(s.CollectionId))
                    .OrderBy(x => x.Code).ToList();

            if (string.IsNullOrEmpty(SecondGroup))
                return dbContext.Spec.Where(s => s.FirstGroup == FirstGroup && s.IsCollection == true && string.IsNullOrEmpty(s.CollectionId))
                    .OrderBy(x => x.Code).ToList();
            else
                return dbContext.Spec.Where(s => s.FirstGroup == FirstGroup && s.SecondGroup == SecondGroup &&
                s.IsCollection == true && string.IsNullOrEmpty(s.CollectionId))
                    .OrderBy(x => x.Code).ToList();
        }

        public static string AddSpecCollection(this SampleSpec spec, CoreLimsContext dbContext)
        {
            spec.Id = SAMPLE._newId();
            spec.ReleaseStatus = Common.Status.草稿.ToString();
            spec.Version = 1;
            spec.Enable = true;
            spec.IsCollection = true;
            dbContext.Add(spec);
            dbContext.SaveChanges();
            return "指标集添加成功！";
        }

        public static string UpdateSpecCollection(this SampleSpec spec, CoreLimsContext dbContext)
        {
            SampleSpec Spec = SAMPLE.Spec.getSpec(dbContext, spec.Id);
            Spec.CopyCollection(spec);

            dbContext.Update(Spec);
            dbContext.SaveChanges();
            return "指标集更新成功！";
        }

        public static string DeleteSpecCollection(this SampleSpec spec, CoreLimsContext dbContext, string Id)
        {
            SampleSpec Spec = SAMPLE.Spec.getSpec(dbContext, Id);

            // 删除指标集时，检查测试关系表，如果有引用则不能删除。
            var trl = dbContext.TestRelation.FirstOrDefault(s => s.SpecCollectionId == Spec.Id);
            if (trl != null)
            {
                var test = SAMPLE.TestDefinition.getTestDefinition(dbContext, trl.TestDefinitionId);
                return "该指标集与测试 " + test.TestName + " 关联，若要删除该指标集，请先删除关联关系！";
            }

            // 删除指标集时，检查样品定义关系表，如果有引用则不能删除
            var rl = dbContext.Relation.FirstOrDefault(s => s.IncludedId == Spec.Id && s.IncludedTabName == "SpecCollection");
            if (rl != null)
            {
                var sample = SAMPLE.SampleDefinition.getSampleDefinition(dbContext, rl.SourceId);
                return "该指标集与样品 " + sample.Name + " 关联，若要删除该指标集，请先删除关联关系！";
            }

            // 删除指标集时，检查登录样品关系表，如果有引用则不能删除
            var name = SAMPLE.Sample.CheckHasSpecCollection(dbContext, Spec.Id);
            if (name != null)
                return "该指标集与登录样品 " + name + " 关联，若要删除该指标集，请开始或删除该样品！";

            // 删除指标集时，将关联的指标项一块删除
            var collection = SAMPLE.Spec.getSpecCollectionList(dbContext)
                .Where(x => x.CollectionId == Spec.Id)
                .ToList();

            foreach (var item in collection)
                dbContext.Remove(item);

            dbContext.Remove(Spec);
            dbContext.SaveChanges();
            return "删除成功！";
        }

        public static string DeleteSpecCollectionAnalyte(this SampleSpec spec, CoreLimsContext dbContext, string Id)
        {
            SampleSpec Spec = SAMPLE.Spec.getSpec(dbContext, Id);
            dbContext.Remove(Spec);
            dbContext.SaveChanges();
            return "删除成功！";
        }

        public static SampleSpec CopyCollection(this SampleSpec spec, SampleSpec other)
        {
            spec.Code = other.Code;
            spec.Name = other.Name;
            spec.FirstGroup = other.FirstGroup;
            spec.SecondGroup = other.SecondGroup;
            spec.Description = other.Description;

            return spec;
        }

        public static string addSpecCollectionAanylte(this SampleSpec spec, CoreLimsContext dbContext)
        {
            SampleSpec exist = dbContext.Spec.FirstOrDefault(s => s.AnalyteId == spec.AnalyteId && s.CollectionId == spec.CollectionId);
            if (exist != null)
                return "指标集中不能包含重复分析项！";

            SampleSpec Spec = SAMPLE.Spec.getSpec(dbContext, spec.CollectionId);

            spec.Id = SAMPLE._newId();
            spec.Code = Spec.Code;
            spec.Name = Spec.Name;
            spec.FirstGroup = Spec.FirstGroup;
            spec.SecondGroup= Spec.SecondGroup;
            
            spec.ReleaseStatus = Common.Status.草稿.ToString();
            spec.Version = 1;
            spec.Enable = true;
            spec.IsCollection = true;
            dbContext.Add(spec);
            dbContext.SaveChanges();
            return "指标集添加成功！";
        }

        public static IQueryable<object> getSpecCollectionAnayltes(this SampleSpec spec, CoreLimsContext dbContext, string CollectionId)
        {
            var list = dbContext.Spec.Where(s => s.IsCollection == true && s.CollectionId == CollectionId)
                        .Select(s => new { s.AnalyteId })
                        .ToArray();

            string[] array = new string[list.Length];
            for (int i = 0; i < list.Length; i++)
            {
                array[i] = list[i].AnalyteId;
            }

            var analist = from analyte in dbContext.Analyte
                          join specCollect in dbContext.Spec on analyte.Id equals specCollect.AnalyteId
                          where (array.Contains(analyte.Id) && specCollect.CollectionId == CollectionId)
                          select new { specCollect.Id, analyte.Code, analyte.Name , analyte.Classification, analyte.ResultModel,
                              analyte.RoundingOff, analyte.Units, specCollect.LowA, specCollect.LowB,specCollect.StandardValue,
                              specCollect.HighB, specCollect.HighA ,specCollect.AcceptanceCriteria};

            return analist;
        }

        /// <summary>
        /// 根据 指标集ID 和 分析项ID 获得对应的指标
        /// </summary>
        /// <param name="spec"></param>
        /// <param name="dbContext"></param>
        /// <param name="CollectionId"></param>
        /// <param name="AnalyteId"></param>
        /// <returns></returns>
        public static IQueryable<object> getSpecCollectionAnaylte(this SampleSpec spec, CoreLimsContext dbContext, string CollectionId, string AnalyteId)
        {
            var analist = from analyte in dbContext.Analyte
                          join specCollect in dbContext.Spec on analyte.Id equals specCollect.AnalyteId
                          where (specCollect.AnalyteId == AnalyteId && specCollect.CollectionId == CollectionId)
                          select new
                          {
                              specCollect.Id,
                              analyte.Code,
                              analyte.Name,
                              analyte.Classification,
                              analyte.ResultModel,
                              analyte.RoundingOff,
                              analyte.Units,
                              specCollect.LowA,
                              specCollect.LowB,
                              specCollect.HighB,
                              specCollect.HighA,
                              specCollect.AcceptanceCriteria,
                              specCollect.AnalyteId
                          };

            return analist;
        }
        #endregion
    }

}
